#include <iostream>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"

const int gnum = 5;
Task t;

class EndPoint
{
private:
    static int number;
public:
    pid_t _child_id;
    int _write_fd;
    std::string processname;
public:
    EndPoint(pid_t id, int fd):_child_id(id), _write_fd(fd)
    {
        char namebuffer[64];
        snprintf(namebuffer, sizeof(namebuffer), "process-%d[%d:%d]", number++, _child_id, _write_fd);
        processname = namebuffer;
    }
    std::string name() const
    {
        return processname;
    }
    ~EndPoint()
    {}
};

int EndPoint::number = 0;

void WaitCommand()
{
    while (true) 
    {
        int command;
        int n = read(0, &command, sizeof(int));
        if (n == sizeof(int))
        {
            t.Execute(command);
        }
        else if (n == 0)
        {
            std::cout << "父进程让我退出，我就退出了: " << getpid() << std::endl;
            break;
        }
        else
        {
            break;
        }
    }
}

void createProcesses(std::vector<EndPoint>* end_point)
{
    std::vector<int> fds;
    for (int i = 0; i < gnum; ++i)
    {
        // 1.1 创建管道
        int pipefd[2] = { 0 };
        int n = pipe(pipefd);
        assert(n == 0);
        (void) n;
        // 1.2 创建子进程
        pid_t id = fork();
        assert(id != -1);
        if (id == 0)
        {
            for (auto& fd:fds) close(fd);
            // 1.3 关闭不要的fd
            close(pipefd[1]);
            // 1.3.1 输入重定向
            dup2(pipefd[0], 0);
            // 1.3.2 子进程开始等待获取指令
            WaitCommand();
            close(pipefd[0]);
            exit(0);
        }
        // 1.3 关闭不要的fd
        close(pipefd[0]);


        // 1.4 将新的子进程和它的进程写端，构建对象
        end_point->push_back(EndPoint(id, pipefd[1]));

        fds.push_back(pipefd[1]);
    }
}

int ShowBoard()
{
    std::cout << "##################################" << std::endl;
    std::cout << "# 0.执行日志任务  1.执行数据库任务 #" << std::endl;
    std::cout << "# 2.执行请求任务  3.退出          #" << std::endl;
    std::cout << "##################################" << std::endl;
    std::cout << "请选择# ";
    int command = 0;
    std::cin >> command;
    return command;
}

void ctrlProcess(const std::vector<EndPoint>& end_points)
{
    int cnt = 0;
    while (true)
    {
        // 1. 选择任务
        int command = ShowBoard();
        if (command == 3) break;
        if (command < 0 || command > 2) continue;
        // 2. 选择进程
        int index = cnt++;
        cnt %= end_points.size();
        std::string name = end_points[index].name();
        std::cout << "选择了进程: " << name << "| 处理任务: " << command << std::endl;
        // 3. 下发任务
        write(end_points[index]._write_fd, &command, sizeof(command));
        sleep(1);
    }
}

void waitProcess(const std::vector<EndPoint>& end_point)
{
    // for (const auto ep : end_point) close(ep._write_fd);
    // std::cout << "父进程让所有子进程退出" << std::endl;
    // sleep(10);
    // for (const auto ep : end_point) waitpid(ep._child_id, nullptr, 0);
    // std::cout << "父进程回收了所有子进程" << std::endl;

    for (int end = 0; end < end_point.size(); ++end)
    {
        // 1. 我们需要让子进程全部退出 --- 只需要让父进程关闭所有的write fd就可以了！
        close(end_point[end]._write_fd);
        std::cout << "父进程让子进程退出, pid: " << end_point[end]._child_id << std::endl;
        // 2. 父进程要回收子进程的僵尸状态
        waitpid(end_point[end]._child_id, nullptr, 0);
    }
}

int main()
{
    std::vector<EndPoint> end_points;
    // 先进行构建控制结构，父进程写入，子进程读取
    createProcesses(&end_points);

    // 
    ctrlProcess(end_points);

    // 处理所有的推出问题
    waitProcess(end_points);
    return 0;
}